package com.hxzy.module.auth.controller;

import cn.hutool.core.util.ObjectUtil;
import com.hxzy.framework.common.constant.AuthConstant;
import com.hxzy.framework.common.constant.RedisConstant;
import com.hxzy.framework.common.exception.ApiException;
import com.hxzy.framework.common.resp.R;
import com.hxzy.framework.common.util.ResultUtil;
import com.hxzy.framework.web.util.WebFrameworkUtils;
import com.hxzy.module.auth.api.auth.resp.Oauth2TokenDto;
import com.hxzy.module.merchant.api.merchant.MerchantFeignApi;
import com.hxzy.module.merchant.api.merchant.resp.MerchantResp;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author wy
 * @Description TODO
 * @Date 2024/1/26 14:42
 * @Version 1.0
 */
@Log4j2
@RestController
@Tag(name = "授权认证-统一认证授权接口")
@RequestMapping("/oauth")
public class AuthController {

    /**
     * 通过 oauth/token 来获取 token,系统自带的类
     */
    @Resource
    private TokenEndpoint tokenEndpoint;


    /**
     * 商户远程访问服务
     */
    @Autowired
    private MerchantFeignApi  merchantFeignApi;

    @Autowired
    private RedisTemplate  redisTemplate;


    /**
     * OAuth授权模式4种：
     *  grant_type=code 授权码， grant_type=password密码式 , grant_type=client_credentials 凭证式  response_type=token  隐藏式
     * @param principal
     * @param parameters
     * @return
     * @throws HttpRequestMethodNotSupportedException
     */
    @Parameters({
            @Parameter(name = "grant_type",example = "password",description = "授权模式(密码模式)",required = true),
            @Parameter(name = "client_id", description = "Oauth2客户端ID",required = true),
            @Parameter(name = "client_secret", description = "Oauth2客户端秘钥",required = true),
            @Parameter(name = "username", description = "登录用户名",required = true),
            @Parameter(name = "password", description = "登录密码",required = true)
    })
    @ApiOperation(value = "Oauth2认证方法")
    @PostMapping(value = "/token")
    public R<Oauth2TokenDto> postAccessToken(@Parameter(hidden = true) Principal principal, @Parameter(hidden = true) @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        // 如果发请的请求  client_id=Admin  或者   client_id=Admin_Slave ，请求头中就必须要另一个参数  merchant_id=商户ID
        HttpServletRequest request = WebFrameworkUtils.getRequest();
        String merchantId=null;
        //获取请求头中的商户id
        if (ObjectUtil.isNotEmpty(request)){
            merchantId=  request.getHeader(AuthConstant.MERCHANT_ID);
        }

        // 调用oauth认证服务  自动调用 com.hxzy.module.auth.service.impl.UserDetailsImpl.loadUserByUsername  类中的方法
        ResponseEntity<OAuth2AccessToken> oAuth2AccessTokenResponseEntity = this.tokenEndpoint.postAccessToken(principal, parameters);
        //获取oauth2.0的令牌信息
        OAuth2AccessToken oAuth2AccessToken = oAuth2AccessTokenResponseEntity.getBody();

        log.info(oAuth2AccessToken.toString());

        //如果这个空，抛出异常
        assert oAuth2AccessToken != null;

        //定义自定义返回对象
        Oauth2TokenDto oauth2TokenDto = Oauth2TokenDto.builder()
                .token(oAuth2AccessToken.getValue())
                .refreshToken(oAuth2AccessToken.getRefreshToken().getValue())
                .expiresIn(oAuth2AccessToken.getExpiresIn())
                .tokenHead(AuthConstant.JWT_TOKEN_PREFIX).build();

        //开始存放到redis里面

        String redisKey=null;
        //判断是否是商户，并且存储到redis中
        if (ObjectUtil.isNotEmpty(merchantId)){
            //查询商户信息
            R<MerchantResp> merchantRespR = this.merchantFeignApi.findMerchantById(Long.parseLong(merchantId));
            MerchantResp merchant = ResultUtil.remoteResult(merchantRespR);
            //判断是否过期
            if (ObjectUtil.isNotEmpty(merchant.getDisableTime())&&merchant.getDisableTime().before(new Date())){
                throw new ApiException(500,"当前商户已经过期，请续费后使用");
            }

            if (merchant.getDisable()){
                throw new ApiException(500,"当前商户已经过期，请续费后使用");
            }

            //构造  authorization: client_id=[Admin后台管理, Admin_Slave 后台分店管理, back_admin 总端后台]
            redisKey = RedisConstant.AUTHORIZATION + parameters.get("client_id") + ":" + parameters.get("username")+merchantId;
        }else {
            redisKey = RedisConstant.AUTHORIZATION + parameters.get("client_id") + ":" + parameters.get("username");
        }

        //存到redis中
        this.redisTemplate.opsForValue().set(redisKey,oauth2TokenDto.getToken(),oauth2TokenDto.getExpiresIn(), TimeUnit.SECONDS );

        return  R.success(oauth2TokenDto);
    }


}
